package com.liang;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用同步锁Lock完成消费者和生产者实例
 * 1、在 Condition 对象中，与 wait、notify 和 notifyAll 方法对应的分别是await、signal 和 signalAll。
 * 2、Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得Condition 实例，请使用其 newCondition() 方法。
 *
 * @author: Liangxp
 * @date: 2019/8/1 23:19
 */
public class TestProduceAndConsumerForLock8 {
    public static void main(String[] args) {
        Clerk2 clerk2 = new Clerk2();

        Produce2 produce2 = new Produce2(clerk2);
        Consumer2 consumer2 = new Consumer2(clerk2);

        new Thread(produce2, "生产者A").start();
        new Thread(consumer2, "消费者B").start();
    }
}

class Clerk2 {

    private int product = 0;

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // 进货
    public void get() {
        lock.lock();

        try {
            // 当货物没有的时候去生产货物
            while (product >= 1) {
                System.out.println("货物已满");
                // 有货的时候进入等待状态
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 没货的时候生产货物，并唤醒消费者卖货
            System.out.println(Thread.currentThread().getName() + "：" + ++product);
            // 唤醒卖货
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    // 卖货
    public void sale() {
        lock.lock();
        try {
            while (product <= 0) {
                System.out.println("缺货");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "："+ --product);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }

}


class Produce2 implements Runnable {
    private Clerk2 clerk2;

    public Produce2(Clerk2 clerk2) {
        this.clerk2 = clerk2;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk2.get();
        }
    }
}

class Consumer2 implements Runnable {

    private Clerk2 clerk2;

    public Consumer2(Clerk2 clerk2) {
        this.clerk2 = clerk2;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk2.sale();
        }
    }
}
